package spring.cloud.tasks.client.item_task_processor.pooled.impl;

import com.google.common.collect.HashBasedTable;
import com.google.common.collect.Interner;
import com.google.common.collect.Interners;
import com.google.common.collect.Table;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import spring.cloud.tasks.client.item_task_processor.TaskProcessor;
import spring.cloud.tasks.client.item_task_processor.pooled.TaskHeartBeatPooled;
import spring.cloud.tasks.client.item_task_processor.pooled.timer_task.TaskHeartBeatTask;
import spring.cloud.tasks.client.item_task_processor.pooled.timer_task.TimerTask;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;


@Slf4j
public class TaskHeartBeatPooledImpl implements TaskHeartBeatPooled, ApplicationListener {
    /**
     * 所有任务运行信息按心跳间隔分组
     */
    public static final Table<String, String, TaskProcessor> heartBeatRateStringToTaskProcessorIdToTaskProcessorMapMap = HashBasedTable.create();
    /**
     * 不同心跳区间不同的定时任务
     */
    private static final Map<String, ScheduledExecutorService> heartBeatRateStringToScheduledExecutorServiceMap = new HashMap<String, ScheduledExecutorService>();
    private static final ScheduledExecutorService HEARTBEAT_SCHEDULE = Executors.newSingleThreadScheduledExecutor();

    private Runnable timerTask = new TimerTask("EXECUTOR", "TASK_RUNTIME_HEARTBEAT") {
        @Override
        public void process() throws Exception {
            Set<String> heartBeatRateStringSet = heartBeatRateStringToScheduledExecutorServiceMap.keySet();
            for (String heartBeatRateString : heartBeatRateStringSet) {
                //必须先将数据放入table再创建线程池
                Map<String, TaskProcessor> taskProcessorIdToTaskProcessorMap = heartBeatRateStringToTaskProcessorIdToTaskProcessorMapMap.row(heartBeatRateString);
                if (taskProcessorIdToTaskProcessorMap != null) {
                    if (taskProcessorIdToTaskProcessorMap.size() == 0) {
                        heartBeatRateStringToTaskProcessorIdToTaskProcessorMapMap.rowMap().remove(heartBeatRateString);
                        ScheduledExecutorService scheduledExecutorService = heartBeatRateStringToScheduledExecutorServiceMap.remove(heartBeatRateString);
                        if (scheduledExecutorService != null) {
                            scheduledExecutorService.shutdown();
                        }
                        log.info("移除{}/s周期的心跳数据队列!", heartBeatRateString);
                    }
                }
            }
        }
    };
    /**
     * 将某个心跳间隔的任务运行信息 添加到 心跳服务定时发送队列
     * 不同间隔周期的定时任务 将数据丢到统一的队列
     * 心跳数据更新任务将队列数据更新或者插入到db
     *
     * @param heartBeatRate
     * @param taskProcessorInfo
     */
    private Interner<String> interner = Interners.newWeakInterner();

    @Override
    public void onApplicationEvent(ApplicationEvent event) {
        HEARTBEAT_SCHEDULE.scheduleWithFixedDelay(timerTask, 1, 1, TimeUnit.SECONDS);
    }

    @Override
    public synchronized void add(Long heartBeatRate, TaskProcessor taskProcessor) {
        String heartBeatRateString = heartBeatRate.toString();
        heartBeatRateStringToTaskProcessorIdToTaskProcessorMapMap.put(heartBeatRateString, taskProcessor.getTaskProcessorInfo().getProcessorId(), taskProcessor);
        //
        if (!heartBeatRateStringToScheduledExecutorServiceMap.containsKey(heartBeatRateString)) {
            synchronized (interner.intern(heartBeatRateString)) {
                if (!heartBeatRateStringToScheduledExecutorServiceMap.containsKey(heartBeatRateString)) {
                    ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();
                    heartBeatRateStringToScheduledExecutorServiceMap.put(heartBeatRateString, scheduledExecutorService);
                    TaskHeartBeatTask taskHeartBeatTask = new TaskHeartBeatTask(heartBeatRateString);
                    scheduledExecutorService.scheduleWithFixedDelay(taskHeartBeatTask, 1, heartBeatRate, TimeUnit.SECONDS);
                }
            }

        }
    }

    @Override
    public synchronized void remove(Long heartBeatRate, TaskProcessor taskProcessor) {
        String heartBeatRateString = heartBeatRate.toString();
        String processorId = taskProcessor.getTaskProcessorInfo().getProcessorId();
        heartBeatRateStringToTaskProcessorIdToTaskProcessorMapMap.remove(heartBeatRateString, processorId);
        //
        // 如果这个间隔不存在需要发送心跳的任务 则清空相关队列
        Map<String, TaskProcessor> taskProcessorIdToTaskProcessorMap = heartBeatRateStringToTaskProcessorIdToTaskProcessorMapMap.row(heartBeatRateString);
        if (taskProcessorIdToTaskProcessorMap != null) {
            taskProcessorIdToTaskProcessorMap.remove(processorId);
            if (taskProcessorIdToTaskProcessorMap.size() == 0) {
                heartBeatRateStringToTaskProcessorIdToTaskProcessorMapMap.rowMap().remove(heartBeatRateString);
                ScheduledExecutorService scheduledExecutorService = heartBeatRateStringToScheduledExecutorServiceMap.remove(heartBeatRateString);
                if (scheduledExecutorService != null) {
                    scheduledExecutorService.shutdown();
                }
                log.info("移除{}/s周期的心跳数据队列!", heartBeatRateString);
            }


        }

    }


}
